<template>
  <div class="container">
    <div>
      <label>输入：</label><input class="input" v-model="question" />
      <button @click="update">提交</button>
    </div>
    <div class="output">
      <div>
        <label>Streaming</label><input type="checkbox" v-model="stream" />
      </div>
      <div>{{ content }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";

const question = ref("讲一个关于中国龙的故事");
const content = ref("");
const stream = ref(true);

const update = async () => {
  if (!question.value) return;
  content.value = "思考中...";

  const endpoint = "https://api.deepseek.com/chat/completions";
  console.log(import.meta.env.VITE_DEEPSEEK_API_KEY,'VITE_DEEPSEEK_API_KEY');
  const headers = {
    "Content-Type": "application/json",
    Authorization: `Bearer ${import.meta.env.VITE_DEEPSEEK_API_KEY}`,
  };

  const response = await fetch(endpoint, {
    method: "POST",
    headers: headers,
    body: JSON.stringify({
      model: "deepseek-chat",
      messages: [{ role: "user", content: question.value }],
      stream: stream.value,
    }),
  });

  // 判断是否启用流式响应模式
  if (stream.value) {
    // 清空之前的内容，准备接收新的流式数据
    content.value = "";

    // 获取响应体的读取器，用于逐块读取数据流
    const reader = response.body?.getReader();
    // 创建文本解码器，将二进制数据转换为文本
    const decoder = new TextDecoder();
    // 标记是否完成读取
    let done = false;
    // 缓冲区，用于存储不完整的数据块
    let buffer = "";

    // 持续读取数据流，直到完成
    while (!done) {
      // 从流中读取一个数据块
      // value: 当前读取的数据块（Uint8Array格式）
      // done: 是否已读取完毕
      const { value, done: doneReading } = await (reader?.read() as Promise<{
        value: any;
        done: boolean;
      }>);
      done = doneReading;
      
      // 将缓冲区的内容与新解码的数据块合并
      // 这样可以处理跨数据块的不完整消息
      const chunkValue = buffer + decoder.decode(value);
      // 重置缓冲区
      buffer = "";

      // 按行分割数据，并过滤出以"data: "开头的行
      // 这是Server-Sent Events (SSE) 的标准格式
      const lines = chunkValue
        .split("\n")
        .filter((line) => line.startsWith("data: "));

      // 处理每一行数据
      for (const line of lines) {
        // 移除"data: "前缀，获取实际的JSON数据
        const incoming = line.slice(6);
        
        // 检查是否收到结束信号
        if (incoming === "[DONE]") {
          done = true;
          break;
        }
        
        try {
          // 尝试解析JSON数据
          const data = JSON.parse(incoming);
          // 提取AI回复的增量内容
          // choices[0].delta.content 包含本次传输的文本片段
          const delta = data.choices[0].delta.content;
          // 如果有内容，就追加到显示区域
          if (delta) content.value += delta;
        } catch (ex) {
          // 如果JSON解析失败，说明数据可能不完整
          // 将这部分数据放回缓冲区，等待下次合并处理
          buffer += `data: ${incoming}`;
        }
      }
    }
  } else {
    // 非流式模式：一次性获取完整响应
    const data = await response.json();
    // 直接设置完整的回复内容
    content.value = data.choices[0].message.content;
  }
};
</script>

<style scoped>
.container {
  display: flex;
  flex-direction: column;
  align-items: start;
  justify-content: start;
  height: 100vh;
  font-size: 0.85rem;
}
.input {
  width: 200px;
}
.output {
  margin-top: 10px;
  min-height: 300px;
  width: 100%;
  text-align: left;
}
button {
  padding: 0 10px;
  margin-left: 6px;
}
</style>
